using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace FrameworkDesign
{
    public interface ITypeEventSystem
    {
        void Send<T>() where T : new();
        void Send<T>(T onEvent);
        IUnRegister Register<T>(Action<T> onEvent);
        void UnRegister<T>(Action<T> onEvent);
    }
    public interface IUnRegister
    {
        void UnRegister();
    }
    public class UnRegisterOnDestroyTrigger : MonoBehaviour
    {
        public HashSet<IUnRegister> mUnRegisters = new HashSet<IUnRegister>();
        public void AddUnRegister(IUnRegister unRegister)
        {
            mUnRegisters.Add(unRegister);
        }
        private void OnDestroy()
        {
            foreach (var unRegister in mUnRegisters)
            {
                unRegister.UnRegister();
            }
            mUnRegisters.Clear();
           
            
        }
    }
    public static class UnRegisterExtension
    {
        public static void UnRegisterEventWhenGameObjectDestory(this IUnRegister self, GameObject gameObject)
        {
            var trigger = gameObject.GetComponent<UnRegisterOnDestroyTrigger>();
            if (trigger == null)
            {
                gameObject.AddComponent<UnRegisterOnDestroyTrigger>();
                trigger = gameObject.GetComponent<UnRegisterOnDestroyTrigger>();
            }
            trigger.AddUnRegister(self);
        }
    }

    public struct TypeEventSystemUnRegister<T> : IUnRegister
    {
        public ITypeEventSystem TypeEventSystem;
        public Action<T> OnEvent;
       
        public void UnRegister()
        {
            TypeEventSystem.UnRegister<T>(OnEvent);
            TypeEventSystem = null;
            OnEvent = null;
        }
    }
    public class TypeEventSystem : ITypeEventSystem
    {
        public interface IRegistrations
        {

        }
        public class Registrations<T> : IRegistrations
        {
            public Action<T> OnEvent = e => { };
        }
        private Dictionary <Type,IRegistrations> mEventRegistration=new Dictionary<Type,IRegistrations>();
        public IUnRegister Register<T>(Action<T> onEvent)
        {
            var type=typeof(T);
            IRegistrations registrations;
            if(mEventRegistration.TryGetValue(type,out registrations))
            {

            }
            else
            {
                registrations = new Registrations<T>();
                mEventRegistration.Add(type, registrations);
            }
            (registrations as Registrations<T>).OnEvent += onEvent;
            return new TypeEventSystemUnRegister<T>()
            {
                OnEvent = onEvent,
                TypeEventSystem = this
            };
        }


        public void Send<T>() where T : new()
        {
            var onEvent = new T();
            Send<T>(onEvent);
        }

        public void Send<T>(T onEvent) 
        {
            var type = typeof(T);
            IRegistrations registrations;
            if (mEventRegistration.TryGetValue(type, out registrations))
            {
                (registrations as Registrations<T>).OnEvent(onEvent);
                //(registrations as Registrations<T>).OnEvent.Invoke(onEvent);
            }
        }

        public void UnRegister<T>(Action<T> onEvent)
        {
            var type = typeof(T);
            IRegistrations registrations;
            if (mEventRegistration.TryGetValue(type, out registrations))
            {
                (registrations as Registrations<T>).OnEvent -= onEvent;
            }
        }
    }
}


